﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using iTFF.WPF.Model.Toaster;
using System.IO;
using iTFF.WPF.View;
using iTFF.WPF.ViewModel;
using System.Xml.Linq;
using System.Windows;
using System.Resources;
using System.Reflection;
using System.Windows.Media;
using iTFF.WPF.Resources.Languages;

namespace iTFF.WPF.CP
{
    class ToasterControlPanel : ViewModelBase, IDisposable
    {

        #region Fields

        ToasterSkin[] _skins;
        string _artworkTempFile;
        ToasterView _toasterView;
        ToasterViewModel _toasterViewModel;

        #endregion

        #region Properties

        /// <summary>
        /// Gets the list of available skins
        /// </summary>
        public ToasterSkin[] Skins
        {
            get
            {
                if (_skins == null)
                    _skins = GetSkinsList();
                return _skins;
            }
        }
        #endregion

        #region Public methods

        /// <summary>
        /// Shows the toast if any playing file
        /// </summary>
        public void ShowToast()
        {

            if (!Settings.Default.ToasterEnable)
                return;

            var track = ControlPanel.Instance.iTunesControlPanel.PlayingTrack;
            if (track == null)
            {
                ControlPanel.Instance.ShowBalloon(Strings.NoPlayingTrackOrBusy, iTFF.WinFormsWrappers.BalloonTipIcon.Info, Strings.NoPlayingTrackOrBusy);
                return;
            }

            MemoryStream memStream = null;

            // save artwork to temp file
            if (track.Artwork.Count > 0)
            {
                track.Artwork[1].SaveArtworkToFile(ArtworkTempFile);

                // create a memorystream for the file, therefore the file will be deleted
                memStream = new MemoryStream(File.ReadAllBytes(ArtworkTempFile));

                try
                {
                    File.Delete(ArtworkTempFile);
                }
                catch (Exception)
                {
                }
            }

            var toasterTrack = new ToasterTrack()
            {
                Title = track.Name,
                Artist = track.Artist,
                Album = track.Album,
                Stars = track.Rating / 20,
                ImageStream = track.Artwork.Count > 0 ? memStream : null
            };

            // if view isn't created, create it
            if (_toasterView == null)
            {

                var currentSkin = CurrentSkin;

                if (currentSkin == null)
                    _toasterView = new ToasterView(false);
                else
                    _toasterView = new ToasterView(currentSkin.IsGlassEffectEnabled);

                // when the window is closed, set _toasterView to null
                _toasterView.Closed += delegate
                {
                    _toasterView = null;
                };

                var trackViewModel = new ToasterTrackViewModel(toasterTrack);
                _toasterViewModel = new ToasterViewModel(trackViewModel);

                // When the ViewModel asks to be closed using the CloseCommand, close the window
                EventHandler handler = null;
                handler = delegate
                {
                    _toasterViewModel.RequestClose -= handler;
                    _toasterView.Close();
                };
                _toasterViewModel.RequestClose += handler;

                // set the datacontext
                _toasterView.DataContext = _toasterViewModel;

                // add the storyboard
                _toasterViewModel.CreateStoryBoard(_toasterView);

                _toasterView.Show();
            }
            else
            {
                // else, update the track
                if (_toasterViewModel != null)
                {
                    _toasterViewModel.ToasterTrack = new ToasterTrackViewModel(toasterTrack);
                    _toasterViewModel.ShowToast();
                }
                _toasterView.Show();
            }

        }

        #endregion

        #region Private methods

        /// <summary>
        /// Gets the list of skins from the namespace
        /// </summary>
        /// <returns></returns>
        private ToasterSkin[] GetSkinsList()
        {
            var assembly = System.Reflection.Assembly.GetExecutingAssembly();

            // search types from correct namespace
            var skins = assembly.GetTypes().Where(t => !string.IsNullOrEmpty(t.Namespace) && t.Namespace.StartsWith("iTFF.WPF.Model.Toaster.UI")).Select(t =>
                new ToasterSkin { Name = t.Name, FullName = t.FullName }).ToArray();

            GetSkinsPropertiesFromXmlFile(skins);
            RestoreSkinsPropertiesFromSettings(skins);

            return skins;
        }

        /// <summary>
        /// Gets the properties from the xml file if it exists
        /// </summary>
        /// <param name="skins"></param>
        private void GetSkinsPropertiesFromXmlFile(ToasterSkin[] skins)
        {
            foreach (var s in skins)
            {

                try
                {
                    // try to load the xml
                    var resman = new ResourceManager("iTFF.WPF.g", Assembly.GetExecutingAssembly());

                    var stream = resman.GetStream(string.Format("model/toaster/ui/{0}.xml", s.Name.ToLower()));

                    if (stream == null)
                        continue;

                    string xml;

                    using (StreamReader r = new StreamReader(stream))
                        xml = r.ReadToEnd();

                    if (!string.IsNullOrEmpty(xml))
                    {
                        // parse the xml
                        XDocument doc = XDocument.Parse(xml);

                        var skinxml = doc.Elements().First().Elements("skin").First();

                        // set foregroundColor
                        if (skinxml.Attribute("foregroundColor") != null)
                            s.ForegroundColor = (Color)ColorConverter.ConvertFromString(skinxml.Attribute("foregroundColor").Value);

                        // set description
                        if (skinxml.Attribute("description") != null)
                            s.Description = skinxml.Attribute("description").Value;

                        // isGlassEffectEnabled
                        if (skinxml.Attribute("isGlassEffectEnabled") != null)
                        {
                            bool b;
                            if (bool.TryParse(skinxml.Attribute("isGlassEffectEnabled").Value, out b))
                                s.IsGlassEffectEnabled = b;
                        }
                    }
                }

                catch (Exception e)
                {
                    System.Diagnostics.Debug.WriteLine(string.Format("Toaster skin xml file for {0} is invalid. Error is : {1}", s.Name, e.Message));
                }
            }
        }

        /// <summary>
        /// Restores the skins properties from settings
        /// </summary>
        /// <param name="skins"></param>
        private void RestoreSkinsPropertiesFromSettings(ToasterSkin[] skins)
        {

            // the foreground colors
            if (!string.IsNullOrEmpty(Settings.Default.ToasterForegroundColors))
            {
                try
                {
                    var colors = Settings.Default.ToasterForegroundColors.Split('$');

                    foreach (var colorParts in colors)
                    {

                        var parts = colorParts.Split('*');

                        var name = parts[0];
                        var color = parts[1];

                        var sk = skins.FirstOrDefault(s => s.Name == name);

                        if (sk != null)
                            sk.ForegroundColor = (Color)ColorConverter.ConvertFromString(color);

                    }
                }
                catch (Exception e)
                {
                    System.Diagnostics.Debug.WriteLine(string.Format("Settings for Foreground color are invalid. Error was : {0}", e.Message));
                }
            }
        }

        /// <summary>
        /// Saves the skins properties to the settings
        /// </summary>
        public void SaveSkinsPropertiesFromSettings()
        {
            var skinsstr = new List<string>(Skins.Where(s => s.ForegroundColor != null).Count());

            foreach (var skin in Skins.Where(s => s.ForegroundColor != null))
                skinsstr.Add(string.Format("{0}*{1}", skin.Name, skin.ForegroundColor.ToString()));

            Settings.Default.ToasterForegroundColors = string.Join("$", skinsstr.ToArray());


        }

        #endregion

        #region Private helpers

        private string ArtworkTempFile
        {
            get
            {
                if (_artworkTempFile == null)
                    _artworkTempFile = Path.GetTempFileName();
                return _artworkTempFile;
            }
        }

        private ToasterSkin CurrentSkin
        {
            get { return ControlPanel.Instance.ToasterControlPanel.Skins.FirstOrDefault(s => s.Name == Settings.Default.ToasterSelectedSkin); }
        }

        #endregion

        #region IDisposable Members

        protected override void OnDispose()
        {
            // save the skins settings
            this.SaveSkinsPropertiesFromSettings();


            // delete temp file if existing
            try
            {
                if (_artworkTempFile != null)
                    File.Delete(_artworkTempFile);
            }
            catch (Exception)
            {
            }
            base.OnDispose();
        }

        #endregion
    }
}
